#region Imports

using System;
using System.Collections.Generic;
using NopSolutions.NopCommerce.BusinessLogic.Categories;
using NopSolutions.NopCommerce.BusinessLogic.Products.Specs;
using NopSolutions.NopCommerce.LuceneHelper.Queries;

#endregion

namespace NopSolutions.NopCommerce.LuceneHelper.Tasks
{
    public class SpecificationOptionUpdateTask : BaseTask<SpecificationOptionUpdateTask>
    {
        #region Private

        private SpecificationAttributeOption _specificationAttributeOption;
        private bool _updateProducts = true;

        #endregion

        #region Constructers

        public SpecificationOptionUpdateTask(int specificationAttributeOptionId)
            :base(specificationAttributeOptionId)
        {
        }

        public SpecificationOptionUpdateTask(int specificationAttributeOptionId, bool updateProducts)
            : this(specificationAttributeOptionId)
        {
            _updateProducts = updateProducts;
        }

        public SpecificationOptionUpdateTask(SpecificationAttributeOption specificationAttributeOption)
            :this(specificationAttributeOption.SpecificationAttributeOptionId)
        {
            _specificationAttributeOption = specificationAttributeOption;
        }
        public SpecificationOptionUpdateTask(SpecificationAttributeOption specificationAttributeOption, bool updateProducts)
            : this(specificationAttributeOption.SpecificationAttributeOptionId, updateProducts)
        {
            _specificationAttributeOption = specificationAttributeOption;
        }

        #endregion

        #region Properties

        public int SpecificationAttributeOptionId
        {
            get { return Id; }
        }

        public SpecificationAttributeOption SpecificationAttributeOption
        {
            get
            {
                return _specificationAttributeOption ??
                       (_specificationAttributeOption =
                        SpecificationAttributeManager.GetSpecificationAttributeOptionById(
                            SpecificationAttributeOptionId));
            }
        }

        public bool UpdateProducts
        {
            get { return _updateProducts; }
            set { _updateProducts = value; }
        }

        #endregion

        #region Task

        public override LuceneIndexType IndexType
        {
            get { return LuceneIndexType.SpecificaitonOptions; }
        }

        public override bool RebuildIndex
        {
            get { return false; }
        }

        public override void DoTask(IndexManager indexManager, SearchManager searchManager, IndexWriterWrapper indexer)
        {
            #region Delete existing spec option

            var query = new SpecificationOptionQuery().Where(SpecificationOptionQuery.FIELDS_SPECIFICATION_ATTRIBUTE_OPTION_ID,
                                                       SpecificationAttributeOptionId.ToString());
            indexer.DeleteDocuments(query.Query);

            #endregion

            //Check if the attribute exists (hasn't been deleted).
            if (SpecificationAttributeOption == null) return;

            if (UpdateProducts)
            {
                #region Index related products

                //look for products that have this option and update the product
                var products =
                    searchManager.SearchProducts(
                        new ProductQuery().WithSpecificationsOption(SpecificationAttributeOption)).
                        MapProducts(false);
                indexManager.IndexTasks(products.ToTasks());

                #endregion
            }

            var document = SpecificationAttributeOption.Document();

            #region Index categories

            foreach (var categoryId in DatabaseHelper.GetCategoriesForOption(SpecificationAttributeOptionId))
            {
                var breadCrumbs = CategoryManager.GetBreadCrumb(categoryId);
                document.AddField(SpecificationOptionQuery.FIELDS_CATEGORY_ID, categoryId.ToString());
                foreach (var crumb in breadCrumbs)
                {
                    document.AddField(SpecificationOptionQuery.FIELDS_CATEGORY_ID, crumb.CategoryId.ToString());
                }
            }

            #endregion

            #region Index manufacturers

            foreach (var manufacturerId in DatabaseHelper.GetManufacturersForOption(SpecificationAttributeOptionId))
            {
                document.AddField(SpecificationOptionQuery.FIELDS_MANUFACTURER_ID, manufacturerId.ToString());
            }

            #endregion
    
            indexer.AddDocument(document);
        }

        public override IEnumerable<Func<SpecificationOptionUpdateTask, object>> ComparableProperties()
        {
            return new List<Func<SpecificationOptionUpdateTask, object>>
                       {
                           x => x.UpdateProducts
                       };
        }

        public override void UpdateTask(SpecificationOptionUpdateTask newTask)
        {
            if (!UpdateProducts)
            {
                UpdateProducts = newTask.UpdateProducts;
            }
        }

        #endregion
    }
}